package com.icesoft.core.web.helper.http;

import com.icesoft.core.web.configurer.http.RestTemplateConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class FastRestTemplate {

    private String url;
    private final HttpHeaders headers = new HttpHeaders();
    private String body;
    private MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
    private RestTemplate restTemplate;

    /**
     * 使用body数据进行请求，不要使用addParam方法设置请求参数, APPLICATION_JSON_UTF8
     */
    public static FastRestTemplate builder(String url, String body) {
        return new FastRestTemplate(url, body).contentType(MediaType.APPLICATION_JSON_UTF8);
    }

    /**
     * 使用map参数进行请求
     */
    public static FastRestTemplate builder(String url) {
        return new FastRestTemplate(url);
    }

    /**
     * 使用map参数进行请求
     */
    public static FastRestTemplate builder(String url, Map<String, String> params) {
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            map.add(entry.getKey(), entry.getValue());
        }
        return new FastRestTemplate(url, map);
    }

    /**
     * 使用map参数进行请求
     */
    public static FastRestTemplate builder(String url, MultiValueMap<String, String> params) {
        return new FastRestTemplate(url, params);
    }

    protected FastRestTemplate(String url, String body) {
        this.url = url;
        this.body = body;
    }

    protected FastRestTemplate(String url, MultiValueMap<String, String> params) {
        this.url = url;
        this.params = params;
    }

    protected FastRestTemplate(String url) {
        this.url = url;
        this.params = new LinkedMultiValueMap<>();
    }

    public FastRestTemplate addHeader(String headerName, String headerValue) {
        headers.add(headerName, headerValue);
        return this;
    }

    public FastRestTemplate addHeaders(Map<String, String> map) {
        map.forEach((key, value) -> {
            headers.add(key, value);
        });
        return this;
    }

    public FastRestTemplate contentType(MediaType mediaType) {
        headers.setContentType(mediaType);
        return this;
    }

    public FastRestTemplate addParam(String name, String value) {
        params.add(name, value);
        return this;
    }

    public FastRestTemplate addParams(Map<String, String> map) {
        map.forEach((key, value) -> {
            params.add(key, value);
        });
        return this;
    }

    public FastRestTemplate restTemplate(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
        return this;
    }

    public String get() {
        return get(String.class);
    }

    public <T> T get(Class<T> responseType) {
        return http(responseType, HttpMethod.GET).getBody();
    }

    public <T> T get(ParameterizedTypeReference<T> responseType) {
        return http(responseType, HttpMethod.GET).getBody();
    }

    public String post() {
        return post(String.class);
    }

    public <T> T post(ParameterizedTypeReference<T> responseType) {
        return http(responseType, HttpMethod.POST).getBody();
    }

    public <T> T post(Class<T> responseType) {
        return http(responseType, HttpMethod.POST).getBody();
    }

    public <T> ResponseEntity<T> http(Class<T> responseType, HttpMethod httpMethod) {
        return http(responseType, null, httpMethod);
    }

    public <T> ResponseEntity<T> http(ParameterizedTypeReference<T> responseType, HttpMethod httpMethod) {
        return http(null, responseType, httpMethod);
    }

    private <T> ResponseEntity<T> http(Class<T> responseType1, ParameterizedTypeReference<T> responseType2,
                                       HttpMethod httpMethod) {
        if (restTemplate == null) {
            restTemplate = RestTemplateConfiguration.DEFAULT_REST_TEMPLATE;
        }
        if (headers.getContentType() == null) {
            contentType(MediaType.APPLICATION_FORM_URLENCODED);
        }
        headers.add("x-requested-with", "XMLHttpRequest");
        ResponseEntity<T> responseEntity;
        List<String> uriVariables = new ArrayList<>();
        if (httpMethod == HttpMethod.GET && !params.isEmpty()) {
            if (!url.contains("?")) {
                url = url + "?";
            }
            params.forEach((name, values) -> {
                for (String value : values) {
                    url = url + "&" + name + "={" + name + "}";
                    uriVariables.add(value);
                }
            });
        }
        if (body != null) {
            log.trace("请求url:{}，请求body：{}", url, body);
            log.trace("请求headers:{}，请求httpMethod：{}", headers, httpMethod);
            HttpEntity<String> bodyEntity = new HttpEntity<>(body, headers);
            if (responseType1 != null) {
                responseEntity = restTemplate.exchange(url, httpMethod, bodyEntity, responseType1,
                        uriVariables.toArray());
            } else {
                responseEntity = restTemplate.exchange(url, httpMethod, bodyEntity, responseType2,
                        uriVariables.toArray());
            }
        } else {
            log.debug("请求url:{}，请求params：{}", url, params);
            log.debug("请求headers:{}，请求httpMethod：{}", headers, httpMethod);
            HttpEntity<MultiValueMap<String, String>> paramsEntity = new HttpEntity<>(params, headers);
            if (responseType1 != null) {
                responseEntity = restTemplate.exchange(url, httpMethod, paramsEntity, responseType1,
                        uriVariables.toArray());
            } else {
                responseEntity = restTemplate.exchange(url, httpMethod, paramsEntity, responseType2,
                        uriVariables.toArray());
            }
        }
        if (log.isDebugEnabled()) {
            log.debug("返回结果：{}", responseEntity.toString());
        }
        return responseEntity;
    }

    @Override
    public String toString() {
        return "url:" + url + "\nheaders:" + headers + "\nbody:" + body + "\nparams:" + params;
    }

    public String getUrl() {
        return url;
    }

    public HttpHeaders getHeaders() {
        return headers;
    }

    public String getBody() {
        return body;
    }

    public MultiValueMap<String, String> getParams() {
        return params;
    }

}
